home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / MacStarter Pascal 1.0 / simpleGraph example ƒ / applicationProcs.graph next >
Encoding:
Text File  |  1993-12-11  |  19.4 KB  |  508 lines  |  [TEXT/PJMM]

  1. {*** THIS IS A MODIFICATION OF THE GENERIC applicationProcs.p UNIT TO DO A SIMPLE }
  2. {        GRAPHING PROGRAM USING EXPRESSIONS, SCALEDGRAPHICSDECORATIONS, ETC. *** }
  3.  
  4. { many of the comments are from the original file, applicationProcs.p }
  5.  
  6. { NOTE:  The def. of type GraphDec and its use in MyWin are the main points here; the only changes to }
  7. {             the generic MyWin type are in the methods for SetDefaults and for OpenInRect.  The actual }
  8. {             graphing is done in procedure graphDec.doDraw, as part of the definition of the  "decoration" }
  9. {             class graphDec. }
  10.  
  11.  
  12. unit applicationProcs;
  13.  
  14. { This is the unit that you must modify to create a new application.  This unit }
  15. { uses object definitions from other units, and it is in turn used by the main }
  16. { program, StandardMain.  However, you don't have to make any changes in the }
  17. { other units or in the main program. }
  18.  
  19. { This unit works with StandardMain.p and xWindow.p.  It also requires the }
  20. { presence of certain resources (those in generc.rsrc).  There are many other units }
  21. { in the project as distributed.  You can add those you need to the uses clause below.  }
  22.  
  23. interface
  24.  
  25. uses
  26.     xWindow, expression, xInputDecoration, xExpressionInput, xScaledGraphicsDecoration, xControlDecoration, xFigureDecoration;
  27.  
  28.  
  29. const
  30.  
  31.     maxSleepTime = 5;   { When the main program has no events to process, it "goes to }
  32.           { sleep" and yields processing time to other processes that may be running.  }
  33.           { However, this program still wants to process "idle" events.  The constant }
  34.           { maxSleepTime specifies the longest time this program is willing to sleep }
  35.           { between idle events.  The time is specified in ticks (60 ticks = 1 second), so }
  36.           { a value of 5 corresponds to about 12 idle events per second, which is OK for }
  37.           { most purposes.  However, if you are using idle events to drive a processing }
  38.           { task (such as drawing successive pieces of a graph on each idle event), you }
  39.           { can change this value, setting it as low as 0 if you like, in which case the }
  40.           { Mac will give as little time as possible to other processes. }
  41.  
  42.  
  43.   { The constants defined below are used by the main program to set up the "About }
  44.   { Box" that is displayed when the user chooses "About . . .  " from the apple menu. }
  45.   { Change them as appropriate for the program you are writing. }
  46.  
  47.     ApplicationShortName = 'Generic Application';
  48.          { This is the name of the program displayed in the first line of the Apple }
  49.          { Menu.  In this example, "About Generic Application..." will appear there. }
  50.  
  51.     ApplicationLongName = 'Generic Macintosh Application , version 0.9 ';
  52.         { Provides a fuller description of the program that will be displayed at the }
  53.         { top of the "About Box". }
  54.  
  55.     AuthorName = 'David Eck';
  56.     AuthorAddress1 = 'Hobart and William Smith Colleges';
  57.     AuthorAddress2 = 'Geneva, NY   14456';
  58.     AuthorAddress3 = '(Email Address:   eck@hws.BITNET)';
  59.        { These four items are displayed on the next four lines of the About Box, under }
  60.        { the heading "Created By:"  You can, of course, leave some of these empty, or }
  61.        { use some of them for information other than an address. }
  62.  
  63.     CommentLine = 'This is a shell program that you can use as a basis for writing Macintosh applications.';
  64.        { This line is simply displayed at the bottom of the about box. }
  65.  
  66.  
  67.  
  68. var
  69.     editMenu: MenuHandle;   { These two variables provide references to the File and }
  70.     fileMenu: MenuHandle;    { Edit menus.  The main program requires that they be here. }
  71.  
  72.  
  73. { The following is a list of procedures called by the main program.  You should not}
  74. { remove or change the name or parameter list for any of these procedures.  If your }
  75. { program does not require one of these procedures, just leave its definition blank. }
  76.  
  77. procedure InitializeApplication;
  78.       { Called when the program is first starting up; use this procedure to initialize }
  79.       { any global variables, open any windows that you want to appear automatically }
  80.       { on the screen at startup, etc.  }
  81.  
  82. procedure CleanUpApplication;
  83.       { This is called just before the program ends, to give you a final chance to clean }
  84.       { up.  Most programs will have no use for this.  There is no way to abort program }
  85.       { termination from this procedure. }
  86.  
  87. procedure DoEditMenu (itemNum: integer);
  88.       { The user has chosen the specified item number from the Edit menu.  This }
  89.       { procedure should carry out that command.  (Items in menus are numbered }
  90.       { from the top down, starting with 1.  Separating lines in the menu are numbered}
  91.       { even though they are not really commands.) }
  92.  
  93. procedure DoFileMenu (itemNum: integer;
  94.                             var done: boolean);
  95.       { Perform command number "itemNum" from the File Menu; if the user has chosen }
  96.       { the Quit command, then the parameter "done" should be set to TRUE, unless }
  97.       { the command is canceled in one way or another (for example, if you put up a }
  98.       { dialog box that says "Do you really want to quit?" and the user answers No). }
  99.       {    In this sample program, the only commands in the File menu are New (command }
  100.       { #1),  Close (#2)  and Quit (#4). }
  101.  
  102. procedure DoOtherMenu (menuNum, itemNum: integer);
  103.       { This procedure is here just in case you add more menus to the menu bar.  The }
  104.       { user has selected item number "itemNum" from menu number "menuNum", }
  105.       { and this procedure should carry out that command.   Note that the menu number }
  106.       { used here is the menu ID (or resource number), not the position of the menu in }
  107.       { the menu bar. }
  108.  
  109. procedure UpdateMenus;
  110.       { This procedure is called just BEFORE the user makes a selection from the }
  111.       { menu bar, after the user has clicked in the menu bar, but before any menu is }
  112.       { displayed.  Use this procedure to enable and disable items in the menu, to set }
  113.       { the names of items with changeable names, to check and uncheck items, etc. }
  114.  
  115. procedure ApplicationIdle;
  116.       { This procedure is called periodically,  unless the computer is otherwise occupied }
  117.       { (for example, tied up in a lengthy computation).   See the description of the constant }
  118.       { maxSleepTime above. }
  119.  
  120.  
  121.  
  122. implementation
  123.  
  124.  
  125. type
  126.  
  127.     graphDec = object(xScaledGraphicsWithAxes)
  128.      { decoration containing a set of axes, plus the graph of a function }
  129.             exp: expression;
  130.             procedure SetUp (win: xWindow;
  131.                                         theLeft, theTop, theWidth, theHeight: integer);
  132.             override;
  133.             procedure doDraw;
  134.             override;
  135.             procedure InstallExpression (theExp: expression);
  136.         end;
  137.  
  138.     calcButton = object(xDefaultButton)
  139.       { a button the user can press to draw a graph }
  140.             procedure HandleClick;
  141.             override;
  142.         end;
  143.  
  144.     myWin = object(xWindow)
  145.  
  146.      { Window contains an area for drawing the graph of a function, a button the user }
  147.      { user can press to draw the graph, and five input boxes where the user enters }
  148.      { the expression that defines the function, and the minimum and maximum values }
  149.      { of x and y for use on the graph. }
  150.  
  151.             graph: graphDec;
  152.             calc: calcButton;
  153.             expIn: xExpressionInput;
  154.             xminIn, xmaxIn, yminIn, ymaxIn: xRealInput;
  155.  
  156.             procedure setDefaults;
  157.             override;
  158.             procedure openInRect (title: string;
  159.                                         left, top, right, bottom: integer);
  160.             override;
  161.             procedure doRedraw (badRect: Rect);
  162.             override;
  163.             procedure doContentClick (localPt: Point;
  164.                                         modifiers: longint);
  165.             override;
  166.             procedure doKey (ch: char;
  167.                                         modifiers: longint);
  168.             override;
  169.  
  170.         end;
  171.  
  172. var
  173.     xRef: integer;  { allows access to the variable "x" used in expressions; this is used }
  174.                           { in some of the procedures from the UNIT "expression". }
  175.  
  176.  
  177. procedure graphDec.SetUp (win: xWindow;
  178.                                 theLeft, theTop, theWidth, theHeight: integer);
  179.     begin
  180.         inherited Setup(win, theLeft, theTop, theWidth, theHeight);
  181.         exp := nil;   { initially, no expression is given }
  182.     end;
  183.  
  184. procedure graphDec.doDraw;
  185.     var
  186.         deltaX, x, y, oldX, oldY: extended;
  187.         i: integer;
  188.         cases1, temp, cases2: handle;
  189.     begin
  190.         inherited doDraw;  { draws the axes }
  191.         if exp <> nil then begin    { draw a graph of the expression }
  192.                 cases1 := NewHandle(0);
  193.                 cases2 := NewHandle(0);
  194.                 deltaX := (xmax - xmin) / 100;
  195.                 oldX := xmin;
  196.                 SetVariableValue(xRef, xmin);
  197.                 oldY := exp.valueWithCases(cases1);
  198.                 ForeColor(blueColor);
  199.                 for i := 1 to 100 do begin
  200.                         x := xmin + i * deltaX;
  201.                         SetVariableValue(xRef, x);
  202.                         y := exp.valueWithCases(cases2);
  203.       { The object of the test in the next IF statement is to avoid drawing a connection line }
  204.       { between successive points in the graph unless we are sure that those points should }
  205.       { be connected.  Procedure SameCases, from UNIT expression, tries to check for discontinuities. }
  206.       { NOTE that a more sophisticated way of handling the case where SameCases is false is needed, such }
  207.       {           looking at extra points between the two x-values involved. }
  208.                         if SameCases(cases1, cases2) & (oldX < infinity) & (oldY < infinity) & (x < infinity) & (y < infinity) then
  209.                             DrawLine(oldX, oldY, x, y);
  210.                         oldX := x;
  211.                         oldY := y;
  212.                         temp := cases2;
  213.                         cases2 := cases1;
  214.                         cases1 := temp;
  215.                     end;
  216.                 ForeColor(blackColor);
  217.             end;
  218.     end;
  219.  
  220. procedure graphDec.InstallExpression (theExp: expression);
  221.   { called when there is a new function to be graphed. }
  222.     begin
  223.         if exp <> nil then
  224.             exp.kill;
  225.         exp := theExp;
  226.         forceRedraw;
  227.     end;
  228.  
  229. procedure calcButton.HandleClick;
  230.   { called when user clicks on button to draw a new graph.   The values entered by the }
  231.   { user are retrieved and checked, as is the function definition.  If any error is found, }
  232.   { nothing is done.  Otherwise, the new graph is drawn. }
  233.     var
  234.         e: expression;
  235.         err: boolean;
  236.         x1, x2, y1, y2: extended;
  237.     begin
  238.         with myWin(itsWindow) do begin
  239.                 xminIn.getNumber(x1, err);
  240.                 if err then
  241.                     EXIT(HandleClick);
  242.                 xmaxIn.getNumber(x2, err);
  243.                 if err then
  244.                     EXIT(HandleClick);
  245.                 if x2 <= x1 then begin
  246.                         TellUser('The maximum x value you specify must be larger than your minimum x value.');
  247.                         EXIT(HandleClick);
  248.                     end;
  249.                 yminIn.getNumber(y1, err);
  250.                 if err then
  251.                     EXIT(HandleClick);
  252.                 ymaxIn.getNumber(y2, err);
  253.                 if err then
  254.                     EXIT(HandleClick);
  255.                 if y2 <= y1 then begin
  256.                         TellUser('The maximum y value you specify must be larger than your minimum y value.');
  257.                         EXIT(HandleClick);
  258.                     end;
  259.                 expIn.GetExpression(e, err);
  260.                 if err then
  261.                     graph.InstallExpression(nil)
  262.                 else begin
  263.                         graph.SetCoordinates(x1, x2, y1, y2);
  264.                         graph.InstallExpression(e);
  265.                         expIn.Hilite(0, 32000);
  266.                     end;
  267.             end;
  268.     end;
  269.  
  270. procedure myWin.setDefaults;
  271. { This procedure sets up the defalut appearance of the window, and initializes certain }
  272. { instance variables.  It is called BEFORE the window is opened, by openInRect. }
  273.     begin
  274.         inherited setDefaults;
  275.         SetFeatures([hasGrow, hasZoom, hasGoAway]);
  276.     end;
  277.  
  278. procedure myWin.openInRect (title: string;
  279.                                 left, top, right, bottom: integer);
  280.  
  281. { The purpose of this procedure is to open a window, initialize its data structures, etc. }
  282. { The title is displayed in the title bar of the window; the position and size of the }
  283. { window are determined by the remaining parameters.  (top,left) is the point at the }
  284. { top, left corner of the inside part of the window, and (right,bottom) is the bottom }
  285. { right corner.   Ordinarily, this procedure is called by procedure Open, instead of }
  286. { being used directly. }
  287.  
  288.     var
  289.         frame: xRectangle;
  290.         str: xDisplayString;  { types xRectangle and xDisplayString is defined in UNIT xFigureDecoration }
  291.     begin
  292.  
  293.         inherited openInRect(title, left, top, right, bottom);
  294.  
  295.         new(graph);                                          { install graph-drawing decoration }
  296.         graph.Setup(self, 200, 10, -10, -40);
  297.         graph.SetCoordinates(-5, 5, -5, 5);
  298.  
  299.         new(frame);                                           { install a box around the graph area }
  300.         frame.Setup(self, 198, 8, -8, -38);
  301.         frame.SetNib(2, 2);
  302.  
  303.         new(str);                                                 { install labels for input boxes }
  304.         str.setUp(self, 'xmin =', 10, 60);
  305.         new(str);
  306.         str.setUp(self, 'xmax =', 10, 90);
  307.         new(str);
  308.         str.setUp(self, 'ymin =', 10, 120);
  309.         new(str);
  310.         str.setUp(self, 'ymax =', 10, 150);
  311.         new(str);
  312.         str.setUp(self, 'f(x) =', 5, -25);
  313.  
  314.         new(xminIn);                                                   { install input boxes }
  315.         xminIn.SetUp(self, 65, 55, 110, 24);
  316.         xminIn.SetContentsToNumber(-5);
  317.  
  318.         new(xmaxIn);
  319.         xmaxIn.SetUp(self, 65, 85, 110, 24);
  320.         xmaxIn.SetContentsToNumber(5);
  321.  
  322.         new(yminIn);
  323.         yminIn.SetUp(self, 65, 115, 110, 24);
  324.         yminIn.SetContentsToNumber(-5);
  325.  
  326.         new(ymaxIn);
  327.         ymaxIn.SetUp(self, 65, 145, 110, 24);
  328.         ymaxIn.SetContentsToNumber(5);
  329.  
  330.         new(expIn);
  331.         expIn.Setup(self, 50, -30, -25, 24);
  332.  
  333.         new(calc);                                                                { install button }
  334.         calc.setup(self, 'Graph It!', 50, 10, 100, 20);
  335.  
  336.         SetMinDragWidth(350);
  337.         SetMinDragHeight(210);
  338.  
  339.     end;
  340.  
  341.  
  342. procedure myWin.doRedraw (badRect: Rect);
  343. { This procedure is called when all or part of the stuff in the window needs to be }
  344. { redrawn.  The parameter badRect specifies the region of the window that needs to }
  345. { be redrawn; the usual thing to do is to just ignore it and to redraw the entire }
  346. { window. }
  347. {     This procedure is called, for example, when another window that has been }
  348. { covering this one is moved or closed.  By default, it is also called when the user }
  349. { changes the position of the scroll bar.  In both cases, the widow is erased before }
  350. { the procedure is called.   (Erasing and redrawing the window may not be the effect }
  351. { you want when the window is scrolled; to change this default behaviour, you have }
  352. { to override the procedures doHScroll and doVScroll.) }
  353. {   The default method in xWindow for doRedraw redraws any }
  354. {  xWindowDecorations in the Window.  Some subclasses of xWindow have }
  355. { other responses to the message doContentClick.  Unless you are sure you }
  356. { have no reason to do so, you sould call INHERITED doContentClick in addition }
  357. { to any other redrawing you do for your window. }
  358.     begin
  359.  
  360.         inherited doRedraw(badRect);  { ordinarily, you should call this somewhere in your procedure  }
  361.  
  362.     end;
  363.  
  364.  
  365. procedure myWin.doContentClick (localPt: Point;
  366.                                 modifiers: longint);
  367.   { This procedure is called when the user clicks on the "content region" of the }
  368.   { window.  (If the user clicks on the scroll bar, title bar, or grow box, that is }
  369.   { handled automatically; this procedure is not called in such cases.)   The point }
  370.   { where the user clicked is given by the parameter localPt.  (The point is in "local }
  371.   { coordinates," i.e. is specified relative to the top left corner of the window.) }
  372.   { The parameter modifiers can be used to check whether the shift, command or }
  373.   { option keys were held down when the mouse was clicked.  This sample program }
  374.   { does not respond to clicks. }
  375.   {   The default method in xWindow for doContentClick sends the doClick to any appropriate }
  376.   {  xWindowDecoration in the Window.  Some subclasses of xWindow have }
  377.   { other responses to the message doContentClick.  Unless you are sure you }
  378.   { have no decorations in your window, you sould call INHERITED doContentClick }
  379.   { whenever your procedure does not handle the click itself. }
  380.     begin
  381.         inherited doContentClick(localPt, modifiers);
  382.     end;
  383.  
  384.  
  385. procedure myWin.doKey (ch: char;
  386.                                 modifiers: longint);
  387.   { This procedure is called when the user presses a key, provided this is the front }
  388.   { (or "active") window.  This procedure is not used by the sample program. }
  389.   {  The default method in xWindow for doKey sends a doKey message to any appropriate }
  390.   {  xWindowDecoration in the Window.  Some subclasses of xWindow have }
  391.   { other responses to the message doKey.  Unless you want some other response }
  392.   { to a key, you sould call INHERITED doKey  (or simply do not override this method }
  393.   { in your window class.) }
  394.     begin
  395.         inherited doKey(ch, modifiers)
  396.     end;
  397.  
  398.  
  399. procedure OpenAWindow;
  400. { A very common procedure is one for opening a new window.  In this sample }
  401. { application, this procedure is called by InitializeApplication to open an initial }
  402. { window.  It is also called when the user chooses the command New from the File }
  403. { menu. }
  404.     var
  405.         Win: myWin;
  406.     begin
  407.         new(Win);
  408.         Win.open('Sample Window');
  409.     end;
  410.  
  411.  
  412. { *** Definitions of procedures that are called in the main program.  *** }
  413.  
  414.  
  415. procedure InitializeApplication;
  416.       { Called when the program is first starting up; use this procedure to initialize }
  417.       { any global variables, open any windows that you want to appear automatically }
  418.       { on the screen at startup, etc.  }
  419.     begin
  420.  
  421.         initExpressions;     { initialize UNIT expressions, and create the variable "x" )}
  422.         xRef := CreateVariable('x', 0);
  423.  
  424.         OpenAWindow;
  425.  
  426.     end;
  427.  
  428. procedure CleanUpApplication;
  429.       { This is called just before the program ends, to give you a final chance to clean }
  430.       { up.  Most programs will have no use for this.  There is no way to abort program }
  431.       { termination from this procedure. }
  432.     begin
  433.     end;
  434.  
  435. procedure UpdateMenus;
  436.       { This procedure is called just BEFORE the user makes a selection from the }
  437.       { menu bar, after the user has clicked in the menu bar, but before any menu is }
  438.       { displayed.  Use this procedure to enable and disable items in the menu, to set }
  439.       { the names of items with changeable names, to check and uncheck items, etc. }
  440.     var
  441.         i: integer;
  442.         win: WindowPtr;
  443.     begin
  444.         win := FrontWindow;  { this is the currently active window, or nil if there is none }
  445.         if win = nil then
  446.             DisableItem(fileMenu, 2)
  447.         else
  448.             EnableItem(fileMenu, 2);
  449.     end;
  450.  
  451.  
  452. procedure CloseFrontWindow;
  453.     var
  454.         X: xWindow;
  455.     begin
  456.         if FrontWindow <> nil then
  457.             if window2xWindow(FrontWindow, X) then
  458.                 X.doClose
  459.     end;
  460.  
  461. procedure DoFileMenu (itemNum: integer;
  462.                                 var done: boolean);
  463.       { Perform command number "itemNum" from the File Menu; if the user has chosen }
  464.       { the Quit command, then the parameter "done" should be set to TRUE, unless }
  465.       { the command is canceled in one way or another (for example, if you put up a }
  466.       { dialog box that says "Do you really want to quit?" and the user answers No). }
  467.       {    In this sample program, the only commands in the File menu are New (command }
  468.       { #1),  Close (#2)  and Quit (#4). }
  469.     begin
  470.         case itemNum of
  471.             1:    { New command }
  472.                 OpenAWindow;
  473.             2:    { Close command }
  474.                 CloseFrontWindow;
  475.             4:    { Quit command }
  476.                 done := true;
  477.         end;
  478.     end;
  479.  
  480. procedure DoEditMenu (itemNum: integer);
  481.       { The user has chosen the specified item number from the Edit menu.  This }
  482.       { procedure should carry out that command.  The sample program does not }
  483.       { use these commands. }
  484.     begin
  485.     end;
  486.  
  487. procedure DoOtherMenu (menuNum, itemNum: integer);
  488.       { This procedure is here just in case you add more menus to the menu bar.  The }
  489.       { user has selected item number "itemNum" from menu number "menuNum", }
  490.       { and this procedure should carry out that command.   Note that the menu number }
  491.       { used here is the menu ID (or resource number), not the position of the menu in }
  492.       { the menu bar.   This sample program has no extra menus. }
  493.     begin
  494.     end;
  495.  
  496. procedure ApplicationIdle;
  497.       { This procedure is called periodically--at least six times a second, unless the }
  498.       { computer is otherwise occupied (for example, tied up in a lengthy computation). }
  499.       { (This default procedure simply sends an idle message to the front window, }
  500.       { if any.) }
  501.     var
  502.         X: xWindow;
  503.     begin
  504.         if (FrontWindow <> nil) & (window2xWindow(FrontWindow, X)) then
  505.             X.idle;
  506.     end;
  507.  
  508. end.